#include "Log.h"
#include <Poller.h>
#include <cstdlib>
#include <sys/epoll.h>
#include <utility>
#include <string.h>

namespace muduo{
    // =======================Poller-private=======================
    void Poller::Update(Channel *channel,int op){
        // epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
        struct epoll_event ev;
        ev.data.fd = channel->Fd();
        ev.events = channel->events();
        int ret = epoll_ctl(_epfd,op, channel->Fd(), &ev);
        if(ret < 0 ){
            errorlog << "epoll_ctl error";
        }
    }
    bool Poller::HasChannel(Channel* channel){
        auto iter=_channels.find(channel->Fd());    
        if(iter == _channels.end()){
            return false;
        }
        return true;
    }
    // =======================Poller-public=======================
    Poller::Poller(){
        _epfd = epoll_create(128);
        if(_epfd < 0 ){
            fatallog << "epoll create error";
            return;
        }
    }
    int Poller::get(){
        return _epfd;
    }
    void Poller::UpdateEvent(Channel *channel){

        bool flag = HasChannel(channel);
        if(flag == false){     
            _channels.insert(std::make_pair(channel->Fd(), channel));
            Update(channel, EPOLL_CTL_ADD);
            return;
        }
        Update(channel, EPOLL_CTL_MOD);
    }
    void Poller::RemoveEvent(Channel *channel){
        bool flag = HasChannel(channel);
        if(flag == true){
            _channels.erase(channel->Fd());
        }
        Update(channel, EPOLL_CTL_DEL);
    }
    void Poller::ActiveEvent(std::vector<Channel*>* evs){
        // 因为Poller只负责对事件的直接操作，所以当epoll等待到事件之后，要将就绪事件交给Channel
        // memset(_evs, 0, sizeof(_evs)); 
        int n = epoll_wait(_epfd, _evs, MAXEVENTSLEN, -1);
        if(n < 0){
            if (errno == EINTR) {
                return ;
            }
            fatallog <<"epoll wait error";
            abort();
        }
        for(int i=0;i<n;i++){
            // 查找就绪事件的文件描述符是否被管理
            auto iter = _channels.find(_evs[i].data.fd);
            assert(iter != _channels.end());
            // 将就绪事件设置到Channnel对象中
            iter->second->SetEvents(_evs[i].events);
            evs->push_back(iter->second);
        }
    }
}